package org.dbwebx.flex.control.menu
{

	import flash.display.DisplayObject;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Mouse;
	
	import mx.controls.Alert;
	import mx.controls.Menu;
	import mx.core.UIComponent;
	import mx.events.InterManagerRequest;
	import mx.events.MenuEvent;
	import mx.managers.CursorManager;
	import mx.managers.ISystemManager;
	import mx.utils.StringUtil;
	
	import org.as3commons.logging.ILogger;
	import org.as3commons.logging.LoggerFactory;

	public class BaseMenuGenerator implements IMenuGenerator
	{
		private static const logger:ILogger=LoggerFactory.getClassLogger(BaseMenuGenerator);

		protected var _menu:Menu;

		/**
		 * Anchor component for the menu.
		 * It determines menu position ant it is target for ChevronAction event.
		 */
		protected var anchorViewComponent:UIComponent;

		protected var data:Object;

		protected var menuStructureDataProvider:Array;

		protected var menuStructureMap:Object;

		/**
		 * Main "document" component for the menu'ed item
		 */
		protected var parentViewComponent:Object;

		public function addMenuItem(item:MenuItem, enabled:Boolean=true, addOnlyEnabled:Boolean=false, disableMenuItemDuplicationException:Boolean=true):void
		{
			if ((item == null) || (!enabled && addOnlyEnabled))
				return;
			if (menuStructureMap == null)
			{
				throw new Error("Uninitialized menuStructureMap");
			}
			if (menuStructureMap[item.action] != null)
			{
				if (disableMenuItemDuplicationException)
				{
					logger.warn("Try to add a Duplicate menu item with action '{0}'", item.action);
				}
				else
				{
					throw new Error(StringUtil.substitute("Try to add a Duplicate menu item with action '{0}'", item.action));
				}
			}

			item.enabled=enabled;
			menuStructureDataProvider.push(item);
			menuStructureMap[item.action]=item;
		}

		public function hideMenu():void
		{
			if (_menu)
			{
				_menu.removeEventListener(MenuEvent.ITEM_CLICK, menuItemClickHandler);
				_menu.removeEventListener(MenuEvent.MENU_HIDE, menuHideHandler);
			}
			data=null;
			parentViewComponent=null;
			anchorViewComponent=null;
		}

		public function prepareMenu():void
		{
			if (!_menu)
			{
				_menu=Menu.createMenu(null, menuStructureDataProvider, false);
				if (!_menu)
				{
					throw new Error("Menu is null");
				}
				_menu.labelField="label";
				_menu.iconField="icon";
				_menu.automationName="_baseMenu_";
			}
			else
			{
				Menu.popUpMenu(_menu, null, menuStructureDataProvider);
			}
		}

		public function setupMenuData(dataObject:Object, dataProvider:Array=null, parentViewComponent:Object=null):void
		{
			data=dataObject;
			menuStructureDataProvider=dataProvider;
			this.parentViewComponent=parentViewComponent;
		}

		public function showMenu(anchorViewComponent:UIComponent=null):void
		{
			if (parentViewComponent == null)
			{
				throw new Error("To show menu parentViewComponent is required (but now is null)");
			}

			if (anchorViewComponent == null)
			{
				anchorViewComponent=parentViewComponent as UIComponent;
			}

			if (anchorViewComponent == null)
			{
				throw new Error("To show menu anchorViewComponent is required (but now is null)");
			}

			this.anchorViewComponent=anchorViewComponent;

			_menu.addEventListener(MenuEvent.ITEM_CLICK, menuItemClickHandler, false, 0, true);
			_menu.addEventListener(MenuEvent.MENU_HIDE, menuHideHandler, false, 0, true);
			_menu.addEventListener(MenuEvent.ITEM_ROLL_OUT, listEventHandler);
			_menu.addEventListener(MenuEvent.ITEM_ROLL_OVER, listEventHandler);

			var position:Point=anchorViewComponent.parent.localToGlobal(new Point(anchorViewComponent.x, anchorViewComponent.y));

			_menu.show();
			_menu.move(position.x - _menu.width + anchorViewComponent.width, position.y + anchorViewComponent.height);

			showMenuOnTheScreen(_menu);
		}

		protected function getMenuItem(chevronAcrionName:String):MenuItem
		{
			return MenuItem(menuStructureMap[chevronAcrionName]);
		}

		protected function listEventHandler(event:MenuEvent):void
		{
			if (event.type == MenuEvent.ITEM_ROLL_OVER && event.item.enabled)
			{
				Mouse.show();
			}
			else if (event.type == MenuEvent.ITEM_ROLL_OUT)
			{
				CursorManager.removeCursor(CursorManager.currentCursorID);
			}
		}

		protected function menuHideHandler(event:MenuEvent):void
		{
			hideMenu();
		}

		protected function menuItemClickHandler(event:MenuEvent):void
		{
			Alert.show("Menu item was clicked.", "Menu item");
			anchorViewComponent.dispatchEvent(new MenuItemClickEvent(data, MenuItem(event.item)));
		}

		protected function resetMenuStructure():void
		{
			menuStructureDataProvider=[];
			menuStructureMap={};
		}

		protected function showMenuOnTheScreen(menu:Menu):void
		{
			if (!menu)
				return;

			// Adjust for menus that extend out of bounds
			var sm:ISystemManager=menu.systemManager.topLevelSystemManager;
			var sbRoot:DisplayObject=sm.getSandboxRoot();
			// do x
			var screen:Rectangle;
			var pt:Point=new Point(menu.x, menu.y);
			pt=sbRoot.localToGlobal(pt);

			if (sm != sbRoot)
			{
				var request:InterManagerRequest=new InterManagerRequest(InterManagerRequest.SYSTEM_MANAGER_REQUEST, false, false, "getVisibleApplicationRect");
				sbRoot.dispatchEvent(request);
				screen=Rectangle(request.value);
			}
			else
			{
				screen=sm.getVisibleApplicationRect();
			}

			var shift:Number=pt.x + menu.width - screen.right + 1;
			if (shift > 0)
				menu.x=Math.max(menu.x - shift, 0);

			// now do y
			shift=pt.y + menu.height - screen.bottom + 1;
			if (shift > 0)
				menu.y=Math.max(menu.y - shift, 0);
		}

	}
}